import serial
from datetime import datetime
import time, os
from utils import *
from node_inference import *
import pandas as pd
import json

ser = serial.Serial('COM5', 9600, parity=serial.PARITY_EVEN, bytesize=serial.EIGHTBITS, stopbits=serial.STOPBITS_ONE, timeout=0.5)

if ser.is_open:
    print('串口已经打开')

addr_dict = {
    1: [0x92, 0x62, 0x10, 0x04, 0x22, 0x20],
    2: [0x36, 0x63, 0x10, 0x04, 0x22, 0x20],
    3: [0x35, 0x61, 0x10, 0x04, 0x22, 0x20],
    4: [0x74, 0x63, 0x10, 0x04, 0x22, 0x20],
    5: [0x56, 0x63, 0x10, 0x04, 0x22, 0x20],
    6: [0x95, 0x63, 0x10, 0x04, 0x22, 0x20],
    7: [0x82, 0x62, 0x10, 0x04, 0x22, 0x20],
    8: [0x11, 0x63, 0x10, 0x04, 0x22, 0x20],
    9: [0x58, 0x63, 0x10, 0x04, 0x22, 0x20],
    10: [0x26, 0x62, 0x10, 0x04, 0x22, 0x20],
}

last_send_time = {i: 0 for i in range(1,11)}

while True:
    try:
        t = str(int(time.time() * 1000))
        log_path = f"./log/{t}"
        if not os.path.exists(log_path):
            os.makedirs(log_path)

        # 获知在线的断路器
        online_nodes = []
        for k in addr_dict.keys():
            if send(ser, "clr", addr_dict[k]):
                online_nodes.append(k)

        print(f"当前在线的节点：{online_nodes}")
        pd.DataFrame({"online_nodes": [online_nodes]}).to_json(f"{log_path}/online_nodes.jsonl", mode="a", orient="records", lines=True)

        online_addr_dict = {}
        for k in online_nodes:
            online_addr_dict[k] = addr_dict[k]

        # 开始拓扑收发+推理流程
        nodes = online_nodes
        known_chains = {}
        known_nodes = set()
        depths = {i: [d + 1 for d in range(len(nodes))] for i in nodes}
        parents = {i: -1 for i in nodes}

        total_dict = {
            "round_time": t,
        }
        for node in nodes:
            total_dict[f"node_{node}"] = {
                "index": node,
                "p": -1,
                "possible_depths": depths[node],
                "parent": -1
            }

        for _ in range(len(nodes)):
            # print(last_send_time)
            # 选择一个发送信号的节点
            while True:
                unable_nodes = [node for node in last_send_time.keys() if time.time() - last_send_time[node] < 180] # 需要冷却的暂时无法发送的节点
                nodes_to_select = list(set(nodes).difference(set(known_chains.keys()).union(set(known_nodes)).union(set(unable_nodes)))) # way 1: 推理+不探索已知节点
                # nodes_to_select = list(set(nodes).difference(set(known_chains.keys()).union(set(known_nodes)))) # way 2: 推理+不探索已知节点+选择尽可能未知的节点探索
                if nodes_to_select:
                    break
                time.sleep(1)

            selected_node = nodes_to_select[random.randint(0, len(nodes_to_select)-1)]

            last_send_time[selected_node] = time.time()
            known_chains[selected_node] = explore(ser, selected_node, online_addr_dict) # 这一步耗时
            pd.DataFrame({selected_node: [known_chains[selected_node]]}).to_json(f"{log_path}/known_chains.jsonl", mode="a", orient="records", lines=True)
            if not known_chains[selected_node]: # 列表为空 说明是关闸的节点
                print(f"检测到{selected_node}是关闸节点")
                nodes.remove(selected_node)
                parents[selected_node] = -2
                depths[selected_node] = [-2]
                del known_chains[selected_node]
            update(known_chains, depths, parents)
            for node in nodes:
                if len(depths[node]) == 1:
                    known_nodes.add(node)
            header = not os.path.exists(f"{log_path}/parents.csv")
            pd.DataFrame({k: [parents[k]] if parents[k] is not None else [0] for k in parents}).to_csv(f"{log_path}/parents.csv", index=False, header=header, mode="a")
            # pd.DataFrame({k: [parents[k]] for k in parents}).to_csv(f"{log_path}/parents.csv", index=False, header=header, mode="a")
            pd.DataFrame({k: [depths[k]] for k in depths}).to_csv(f"{log_path}/depths.csv", index=False, header=header, mode="a")

            for node in nodes:
                total_dict['time'] = str(int(time.time() * 1000))
                total_dict[f"node_{node}"]["possible_depths"] = depths[node]
                total_dict[f"node_{node}"]["parent"] = parents[node] if parents[node] is not None else 0
            json_data = json.dumps(total_dict, ensure_ascii=False, cls=CustomEncoder)
            print("数据文件已更新")
            with open(f"{log_path}/data.json", "w") as f:
                f.write(json_data)

            if len(nodes) == len([i for i in nodes if parents[i] != -1]):
                break

        # 获取所有在线节点的功率
        for node in nodes:
            # total_dict[f"node_{node}"]["p"] = send(ser, "read_p", addr_dict[node])
            u = send(ser, "read_u", addr_dict[node])
            i = send(ser, "read_i", addr_dict[node])
            # print(node, u, i)
            total_dict[f"node_{node}"]["p"] =  u * i
        json_data = json.dumps(total_dict, ensure_ascii=False, cls=CustomEncoder)
        # print(json_data)
        print("一轮检测完毕，数据文件已更新")
        with open(f"{log_path}/data.json", "w") as f:
            f.write(json_data)

        # 如果树全部已知，则打印
        if len(nodes) == len([i for i in nodes if parents[i] != -1]):
            from treelib import Node, Tree

            tree = Tree()

            for depth in range(max(v[0] for v in depths.values())):
                for node in nodes:
                    if depths[node][0] == depth + 1:
                        tree.create_node(node, node, parents[node])
                    
            print(tree)
    except:
        print("检测到节点变动，重新开始拓扑识别")
        continue


if __name__ == "__main__":
    result = {
        "time": 1000*int(time.time()),
        "node1": {
            "name": "1",
            "code": "202213123",
            "status": 1,
            "memo": ""
        },
        "node2": {

        }
    }
    

{
    chart: {
        type: 'spline'
    },
    title: {
        text: 'Monthly Average Temperature'
    },
    subtitle: {
        text: 'Source: ' +
            '<a href="https://en.wikipedia.org/wiki/List_of_cities_by_average_temperature" ' +
            'target="_blank">Wikipedia.com</a>'
    },
    xAxis: {
        categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
            'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
        accessibility: {
            description: 'Months of the year'
        }
    },
    yAxis: {
        title: {
            text: 'Temperature'
        },
        labels: {
            format: '{value}°'
        }
    },
    tooltip: {
        crosshairs: true,
        shared: true
    },
    plotOptions: {
        spline: {
            marker: {
                radius: 4,
                lineColor: '#666666',
                lineWidth: 1
            }
        }
    },
    series: [{
        name: 'Tokyo',
        marker: {
            symbol: 'square'
        },
        data: [5.2, 5.7, 8.7, 13.9, 18.2, 21.4, 25.0, {
            y: 26.4,
            marker: {
                symbol: 'url(https://www.highcharts.com/samples/graphics/sun.png)'
            },
            accessibility: {
                description: 'Sunny symbol, this is the warmest point in the chart.'
            }
        }, 22.8, 17.5, 12.1, 7.6]

    }, {
        name: 'Bergen',
        marker: {
            symbol: 'diamond'
        },
        data: [{
            y: 1.5,
            marker: {
                symbol: 'url(https://www.highcharts.com/samples/graphics/snow.png)'
            },
            accessibility: {
                description: 'Snowy symbol, this is the coldest point in the chart.'
            }
        }, 1.6, 3.3, 5.9, 10.5, 13.5, 14.5, 14.4, 11.5, 8.7, 4.7, 2.6]
    }]
}
